#ifndef __KERNEL_FOR_API__
#define __KERNEL_FOR_API__

#include <sys/types.h>
#include <asm-i386/types.h>
#include <stdint.h>

//typedef unsigned int size_t;
//typedef long long uint64_t;

#define S_IFMT  00170000
#define S_IFSOCK 0140000
#define S_IFLNK	 0120000
#define S_IFREG  0100000
#define S_IFBLK  0060000
#define S_IFDIR  0040000
#define S_IFCHR  0020000
#define S_IFIFO  0010000
#define S_ISUID  0004000
#define S_ISGID  0002000
#define S_ISVTX  0001000

#define S_ISLNK(m)	(((m) & S_IFMT) == S_IFLNK)
#define S_ISREG(m)	(((m) & S_IFMT) == S_IFREG)
#define S_ISDIR(m)	(((m) & S_IFMT) == S_IFDIR)
#define S_ISCHR(m)	(((m) & S_IFMT) == S_IFCHR)
#define S_ISBLK(m)	(((m) & S_IFMT) == S_IFBLK)
#define S_ISFIFO(m)	(((m) & S_IFMT) == S_IFIFO)
#define S_ISSOCK(m)	(((m) & S_IFMT) == S_IFSOCK)

#define S_IRWXU 00700
#define S_IRUSR 00400
#define S_IWUSR 00200
#define S_IXUSR 00100

#define S_IRWXG 00070
#define S_IRGRP 00040
#define S_IWGRP 00020
#define S_IXGRP 00010

#define S_IRWXO 00007
#define S_IROTH 00004
#define S_IWOTH 00002
#define S_IXOTH 00001

/* 1 << 12 on i386*/
#define PAGE_SIZE (1UL << PAGE_CACHE_SHIFT)
#define PAGE_SHIFT 12

#define PAGE_CACHE_SIZE (1 << PAGE_CACHE_SHIFT)
#define PAGE_CACHE_SHIFT 12
struct inode;
struct dentry;
struct super_block;
struct file_system_type;

#define DT_UNKNOWN	0
#define DT_DIR		4
#define DT_REG		8

struct inode_operations {
	int (*create) (struct inode *, struct dentry *, int, void *);
	int (*unlink) (struct inode *, struct dentry *);
	int (*mkdir) (struct inode *, struct dentry *, int);
	int (*rmdir) (struct inode *, struct dentry *);
	int (*read) (struct inode *, uint32_t, uint32_t *, uint32_t *);
	int (*write) (struct inode *, uint64_t, uint32_t, const void *, uint32_t *);
};

struct super_operations {
	struct inode *(*alloc_inode)(struct super_block *sb);
	void (*destroy_inode)(struct inode *);
	void (*read_inode) (struct inode *);
	void (*dirty_inode) (struct inode *);
	int (*write_inode) (struct inode *, int);
	void (*put_inode) (struct inode *);
	void (*drop_inode) (struct inode *);
	void (*delete_inode) (struct inode *);
	void (*put_super) (struct super_block *);
	void (*write_super) (struct super_block *);
	int (*sync_fs)(struct super_block *sb, int wait);
};

struct super_block {
	struct super_operations *s_op;
	struct file_system_type *s_type;
	struct dentry *s_root;
	void *s_fs_info;	/* Filesystem private info */
};

struct file_system_type {
	const char *name;
	int fs_flags;
	struct super_block *(*get_sb) (struct file_system_type *, int, const char *, void *);
	void (*kill_sb) (struct super_block *);
};

struct dentry {
	struct inode *d_inode;
	char *d_name;
	uint8_t d_namelen;
	struct dentry *d_parent;
	// struct list_head sub_dirs;
	//struct dentry_operations d_op;
	struct super_block *d_sb;
	void *d_fs_data;	/* fs-specific data */
};

struct inode {
	unsigned long i_ino;
	umode_t i_mode;
	struct dentry *i_parent;
	struct inode_operations *i_op;
	//struct file_operations *i_fop;
	nlink_t i_nlink;
	struct super_block *i_sb;
};

struct kvec {
	void *iov_base; /* and that should *never* hold a userland pointer */
	size_t iov_len;
};

/* LIST IMPLEMENTATION (from linux/list.h) */
struct list_head {
	struct list_head *next, *prev;
};

#define LIST_HEAD_INIT(name) { &(name), &(name) }

#define LIST_HEAD(name) \
	struct list_head name = LIST_HEAD_INIT(name)

#define INIT_LIST_HEAD(ptr) do { \
	(ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0)

static inline void __list_add(struct list_head *new,
							struct list_head *prev,
							struct list_head *next)
{
	next->prev = new;
	new->next = next;
	new->prev = prev;
	prev->next = new;
}

static inline void list_add(struct list_head *new, struct list_head *head)
{
	__list_add(new, head, head->next);
}

static inline void list_add_tail(struct list_head *new, struct list_head *head)
{
	__list_add(new, head->prev, head);
}

static inline void __list_del(struct list_head *prev, struct list_head *next)
{
	next->prev = prev;
	prev->next = next;
}

static inline void list_del(struct list_head *entry)
{
	__list_del(entry->prev, entry->next);
	entry->next = (void *) 0;
	entry->prev = (void *) 0;
}

static inline int list_empty(const struct list_head *head)
{
	return head->next == head;
}

#define list_entry(ptr, type, member) \
	((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))

#define list_for_each_entry(pos, head, member)					\
	for (pos = list_entry((head)->next, typeof(*pos), member);	\
		&pos->member != (head);									\
		pos = list_entry(pos->member.next, typeof(*pos), member))

#define list_for_each_entry_safe(pos, n, head, member)			\
	for (pos = list_entry((head)->next, typeof(*pos), member),	\
		n = list_entry(pos->member.next, typeof(*pos), member);	\
	     &pos->member != (head); 					\
	     pos = n, n = list_entry(n->member.next, typeof(*n), member))

#define min_t(type,x,y) \
	({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
#define max_t(type,x,y) \
	({ type __x = (x); type __y = (y); __x > __y ? __x: __y; })

#define kmalloc(a,b) malloc((a))
#define je16_to_cpu(x) (x)
#define je32_to_cpu(x) (x)
#define cpu_to_je16(x) (x)
#define cpu_to_je32(x) (x)

#endif /* __KERNEL_FOR_API__ */
